<html>
<head><meta charset="utf-8"><title>What will GATs allow streaming iterators to do differently? · general · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/index.html">general</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html">What will GATs allow streaming iterators to do differently?</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="227608042"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227608042" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227608042">(Feb 24 2021 at 14:40)</a>:</h4>
<p>Today, if one wants to have a streaming iterator approximation, you can use a trait like:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">trait</span><span class="w"> </span><span class="n">StreamingIterator</span><span class="o">&lt;'</span><span class="na">a</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">Item</span>: <span class="o">'</span><span class="na">a</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">next</span><span class="p">(</span><span class="o">&amp;'</span><span class="na">a</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="bp">Self</span>::<span class="n">Item</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>The GATs RFC says that we would rather write it like this:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">trait</span><span class="w"> </span><span class="n">StreamingIterator</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">Item</span><span class="o">&lt;'</span><span class="na">a</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">next</span><span class="o">&lt;'</span><span class="na">a</span><span class="o">&gt;</span><span class="p">(</span><span class="o">&amp;'</span><span class="na">a</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nb">Option</span><span class="o">&lt;</span><span class="bp">Self</span>::<span class="n">Item</span><span class="o">&lt;'</span><span class="na">a</span><span class="o">&gt;&gt;</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>I'm having trouble verbalizing what the benefits of the GAT-enabled version are / the limitations of the current form. Unfortunately for me, the RFC doesn't go to that level.</p>



<a name="227608637"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227608637" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Steven Fackler <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227608637">(Feb 24 2021 at 14:45)</a>:</h4>
<p>I tried to make a streaming iterator definition like you first one a while ago, and things become extremely hairy when you start trying to add in utility methods and adaptors (for_each, filter, etc)</p>



<a name="227608668"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227608668" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Steven Fackler <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227608668">(Feb 24 2021 at 14:45)</a>:</h4>
<p>lots of extremely bizarre lifetime errors</p>



<a name="227608739"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227608739" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Steven Fackler <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227608739">(Feb 24 2021 at 14:45)</a>:</h4>
<p>and because you have to name the lifetime in the first definition it can't be used in some contexts, even with use of <code>for&lt;'a&gt; T: StreamingIterator&lt;'a&gt;</code></p>



<a name="227609100"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227609100" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227609100">(Feb 24 2021 at 14:48)</a>:</h4>
<p>I know that you did, and I was hoping you'd respond here <span aria-label="wink" class="emoji emoji-1f609" role="img" title="wink">:wink:</span> I've even linked to your crate from the related Stack Overflow questions.</p>



<a name="227609553"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227609553" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227609553">(Feb 24 2021 at 14:51)</a>:</h4>
<p>Maybe I need to (attempt to) add <code>filter</code> and see how it falls apart.</p>



<a name="227610360"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227610360" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Steven Fackler <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227610360">(Feb 24 2021 at 14:56)</a>:</h4>
<p>Oh yeah, one of the main problems is that if you want your iterator to return a value borrowed from itself, that just doesn't really work with respect to naming the trait it implements.</p>



<a name="227610395"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227610395" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Steven Fackler <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227610395">(Feb 24 2021 at 14:57)</a>:</h4>
<p>e.g. <code>Box&lt;dyn StreamingIterator&lt;'self??&gt;</code></p>



<a name="227613106"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227613106" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227613106">(Feb 24 2021 at 15:13)</a>:</h4>
<p>I find that <code>for&lt;'lt&gt; LendingIterator&lt;'lt&gt;</code> and <code>LendingIteratorGat</code> (let's start using the <code>Lend</code> word to avoid ambiguity with <code>LendingStreams</code> in the <code>async</code> world) work very similarly in practice (except for the nicer ergonomics for the one on the right, and some compiler bugs dealing with higher-order type-equality constraints), except for one thing: the <code>Gat</code> version is actually expressing: <code>for&lt;'lt where Self : 'lt&gt; LendingIterator&lt;'lt&gt;</code>, and this is something that becomes noticeable when <code>Self</code> is not <code>'static</code>.</p>
<p>In that regard, the closer non-GAT definition is actually:</p>
<div class="codehilite" data-code-language="Diff"><pre><span></span><code>  trait LendingIterator&lt;'next&gt; {
<span class="gd">-     type Item : 'next;</span>
<span class="gi">+     type Item;</span>
      fn next (self: &amp;'next mut Self) -&gt; Option&lt;Self::Item&gt;
<span class="gi">+     where</span>
<span class="gi">+         Self : 'next,</span>
<span class="gi">+         Self::Item : 'next, /* I don't even know if this one is really needed */</span>
      ;
}
</code></pre></div>



<a name="227614338"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227614338" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227614338">(Feb 24 2021 at 15:20)</a>:</h4>
<p>Lending is indeed nice to avoid the ambiguity, but has the hump to overcome of the existing literature :-)</p>



<a name="227615561"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227615561" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227615561">(Feb 24 2021 at 15:28)</a>:</h4>
<p>A good reason to start using it ASAP <span aria-label="stuck out tongue" class="emoji emoji-1f61b" role="img" title="stuck out tongue">:stuck_out_tongue:</span>  Current literature could say: <em><code>LendingIterator</code> (or <code>StreamingIterator</code>, as it was historically named), …</em> That and some update in <code>{fallible_,}streaming_iterator</code> main docs to mention the new name, so as to allow people to make the connection between the two names.</p>



<a name="227626436"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227626436" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227626436">(Feb 24 2021 at 16:23)</a>:</h4>
<p><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=409843215f17b27ba693d5fb74e8cc69">both attempts seem to fail spectacularly</a> at my <code>Filter</code> attempt — I'm I still too sleepy to see a simple mistake I've made?</p>



<a name="227627208"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227627208" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthew Jasper <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227627208">(Feb 24 2021 at 16:27)</a>:</h4>
<p>You need to use <code>P: FnMut(&amp;I::Item) -&gt; bool,</code></p>



<a name="227627417"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227627417" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227627417">(Feb 24 2021 at 16:28)</a>:</h4>
<p>haha, yes</p>



<a name="227627464"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227627464" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227627464">(Feb 24 2021 at 16:28)</a>:</h4>
<p>well, I actually don't follow why</p>



<a name="227627489"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227627489" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227627489">(Feb 24 2021 at 16:28)</a>:</h4>
<p>since they should be the same type</p>



<a name="227627583"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227627583" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Matthew Jasper <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227627583">(Feb 24 2021 at 16:29)</a>:</h4>
<p>Yes, but to normalize <code>Self::Item</code> the predicates of the impl need to be checked, which requires normalizing <code>Self::Item</code>.</p>



<a name="227629273"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227629273" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227629273">(Feb 24 2021 at 16:37)</a>:</h4>
<p>So the next problem is more of a borrowchecker problem than a GATs problem, IMO:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="bp">Self</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="n">inner</span><span class="p">,</span><span class="w"> </span><span class="n">predicate</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">;</span><span class="w"></span>

<span class="k">while</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">inner</span><span class="p">.</span><span class="n">next</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">predicate</span><span class="p">(</span><span class="o">&amp;</span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">v</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="nb">None</span><span class="w"></span>
</code></pre></div>
<div class="codehilite"><pre><span></span><code>error[E0499]: cannot borrow `*inner` as mutable more than once at a time
  --&gt; src/lib.rs:75:33
   |
61 |     impl&lt;&#39;a, I, P&gt; LendingIterator&lt;&#39;a&gt; for Filter&lt;I, P&gt;
   |          -- lifetime `&#39;a` defined here
...
75 |             while let Some(v) = inner.next() {
   |                                 ^^^^^-------
   |                                 |
   |                                 `*inner` was mutably borrowed here in the previous iteration of the loop
   |                                 argument requires that `*inner` is borrowed for `&#39;a`
</code></pre></div>
<p>E.g. that's NLL case <a href="https://github.com/rust-lang/rust/issues/3">#3</a>.</p>



<a name="227679921"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227679921" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227679921">(Feb 24 2021 at 21:57)</a>:</h4>
<p>I don't think you are yet in the NLL case <a href="https://github.com/rust-lang/rust/issues/3">#3</a>: try to use the following function body: <code>let _fst = inner.next(); return inner.next();</code> you will get a similar error to the one you've just shown.<br>
This is because given your bounds the only <code>inner.next()</code> call possible is one with the outer <code>'a</code> lifetime, and that will be a lifetime that spans beyond the rest of the function body even with polonius.</p>
<p>As I mentioned in my previous post, <code>LendingIteratorGat</code> is equivalent to a higher-order bound in the non-Gat world:</p>
<div class="codehilite" data-code-language="Diff"><pre><span></span><code>    impl&lt;'a, I, P&gt; StreamingIterator&lt;'a&gt; for Filter&lt;I, P&gt;
    where
<span class="gd">-       I: StreamingIterator&lt;'a&gt;,</span>
<span class="gi">+       I: for&lt;'__&gt; StreamingIterator&lt;'__&gt;, // can be called with local var / short-lived lifetimes</span>
<span class="gd">-       P: FnMut(&amp;I::Item) -&gt; bool, // &lt;I as StreamingIterator&lt;'a&gt;&gt;::Item</span>
<span class="gi">+       P: FnMut(&amp;&lt;I as StreamingIterator&lt;'_&gt;&gt;::Item) -&gt; bool, // predicate can be applied to borrows to short-lived items</span>
    {
<span class="gd">-       type Item = I::Item; // &lt;I as StreamingIterator&lt;'a&gt;&gt;::Item;</span>
<span class="gi">+       type Item = &lt;I as StreamingIterator&lt;'a&gt;&gt;::Item; // Need to be explicit now</span>
</code></pre></div>
<ul>
<li><a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=64311f9ab41f1a5d86d018f7673ec560">Playground</a></li>
</ul>
<p>That's when you reach NLL <a href="https://github.com/rust-lang/rust/issues/3">#3</a>: the span of the borrow of the <code>.next()</code> call is "chosen dynamically" due to the conditional <code>return</code> (my practical approach to identify NLL <a href="https://github.com/rust-lang/rust/issues/3">#3</a> if <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2018&amp;gist=1da6c51b52650674549414d6c6d16902">replacing <code>return</code> with <code>break</code> avoids the problem</a></p>



<a name="227682779"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/227682779" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jake Goulding <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#227682779">(Feb 24 2021 at 22:09)</a>:</h4>
<p>Even then, this is a bit of a digression — perhaps you'd be able to show something that a GAT-enabled lending iterator trait can do that the non-GAT one cannot?</p>



<a name="228154288"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/228154288" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#228154288">(Feb 28 2021 at 20:22)</a>:</h4>
<p>I have been tinkering a bit with these things (playground with some relevant stuff: <a href="https://play.rust-lang.org/?version=nightly&amp;mode=debug&amp;edition=2018&amp;gist=11fa4dd4e5abccbb98cd42d068797687">https://play.rust-lang.org/?version=nightly&amp;mode=debug&amp;edition=2018&amp;gist=11fa4dd4e5abccbb98cd42d068797687</a>), and I observe the following:</p>
<ul>
<li>
<p>GATs, at least for a <code>LendingIterator</code>, are just sugar for some cases; mainly the <code>I : gat::LendingIterator</code> bound has to be written as <code>I : for&lt;'next&gt; non_gat::LendingIterator&lt;'next&gt;</code>. It's "just" a detail, but pervasive enough one to ultimately warrant having GATs. That being said, the moment you want to mention the (generic) associated type, both syntaxes become impressively similar: <code>I : for&lt;'next&gt; gat::LendingIterator&lt;Item&lt;'next&gt; = String&gt;</code> <em>vs.</em> <code>I : for&lt;'next&gt; non_gat::LendingIterator&lt;'next, Item = String&gt;</code>. But other than that I have been able to write all the properties of <code>gat::LendingIterator</code> using a <code>non_gat::LendingIterator</code> trait; the inverse is actually not true (<em>e.g.</em>, the possibility of bounding the lifetime parameter in some cases), but did not lead to any enhanced usability anyways (the moment the lifetime parameter is bound, it becomes incompatible with the <code>for&lt;'next&gt; non_gat::LendingIterator&lt;'next&gt;</code> bound).</p>
</li>
<li>
<p>In both cases, it is impossible to both use <code>I : …LendingIterator…</code> as well as showcase a definition of <code>type Item&lt;'next&gt; = …</code>, <code>where Self : 'next;</code>. This is the <strong>first deal breaker</strong> with GATs as of now, since in my above example for a lending iterator of <code>T</code>s out of a <code>&amp;'_ [RefCell&lt;T&gt;]</code>, we currently need an over-restrictive <code>T : 'static</code> bound, otherwise the definition <code>type Item&lt;'next&gt; = &amp;'next T;</code> is ill-defined. Granted, an _implicit_ <code>where T : 'next</code> bound on that associated type definition that would then propagate to the whole impl could work, but ultimately, it may conflict with a <code>I : for&lt;'any&gt; gat::LendingIterator&lt;Item&lt;'any&gt;…&gt;</code> bound.</p>
</li>
<li>
<p>The <strong>second deal breaker</strong> is, of course, the bugs related to the trait solver "resolving" that two types are the same. Without solving that, for instance, a fully general <code>.map()</code> adaptor is impossible to write <em>and use</em> (which also requires, incidentally, <code>unboxed_closures</code>, since it is currently impossible to write <code>F : FnOnce(&amp;'_ String) -&gt; R&lt;'_&gt;</code>; one has to write <code>F : for&lt;'arg&gt; FnOnce&lt;(&amp;'arg String,)&gt;</code>, and then use <code>type R&lt;'a&gt; = &lt;F as FnOnce&lt;(&amp;'a String,)&gt;&gt;::Output</code>).</p>
</li>
</ul>



<a name="228622562"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/228622562" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> cynecx <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#228622562">(Mar 03 2021 at 16:31)</a>:</h4>
<p><span class="user-mention" data-user-id="232018">@Daniel Henry-Mantilla</span>  The second issue  might be related to <a href="https://github.com/rust-lang/rust/issues/79768#issuecomment-774152415">https://github.com/rust-lang/rust/issues/79768#issuecomment-774152415</a> and <a href="https://github.com/rust-lang/rust/issues/76407">https://github.com/rust-lang/rust/issues/76407</a>? (iiuc, this isn't a bug in GATs but it's related to the issue around lazy-normalization).</p>



<a name="228631729"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/228631729" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#228631729">(Mar 03 2021 at 17:26)</a>:</h4>
<p>Yes, that's the issue indeed (it comes and goes under different shapes, and is related to using "higher-order associated types")</p>



<a name="229123071"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/229123071" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#229123071">(Mar 06 2021 at 19:38)</a>:</h4>
<p><span class="user-mention" data-user-id="116155">@Jake Goulding</span> another big difference between gat and non-gat (leading to even major ergonomic hits in order to emulate the behavior with non-GAT traits, as showcased <a href="https://play.rust-lang.org/?version=nightly&amp;mode=debug&amp;edition=2018&amp;gist=16b72a60f7201c676196c601f6c2d14b">here</a>, is regarding default methods and them being implemented using the higher-order nature of another method (and I guess the same may happen with recursive default methods):</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">trait</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">T</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>

<span class="w">    </span><span class="k">fn</span> <span class="nf">get</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="w"> </span><span class="p">(</span><span class="n">_</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">thing</span> <span class="p">())</span><span class="w"> </span>-&gt; <span class="nc">Self</span>::<span class="n">T</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>

<span class="w">    </span><span class="k">fn</span> <span class="nf">foo</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">thing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">();</span><span class="w"> </span><span class="c1">// local</span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span>: <span class="nc">Self</span>::<span class="n">T</span><span class="o">&lt;'</span><span class="nb">_</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">Self</span>::<span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="cm">/* 'local */</span><span class="w"> </span><span class="n">thing</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="err">…</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Basically within a GAT trait, <em>its higher-order nature is present everywhere</em>, which is not true for its naive non-GAT polyfill:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="n">trait_alias</span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">trait</span><span class="w"> </span><span class="n">Trait</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">for</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Trait_</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="k">trait</span><span class="w"> </span><span class="n">Trait_</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">T</span><span class="p">;</span><span class="w"></span>

<span class="w">    </span><span class="k">fn</span> <span class="nf">get</span><span class="w"> </span><span class="p">(</span><span class="n">_</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">thing</span> <span class="p">())</span><span class="w"> </span>-&gt; <span class="nc">Self</span>::<span class="n">T</span><span class="p">;</span><span class="w"> </span><span class="cm">/* &lt;Self as Trait_&lt;'thing&gt;&gt;::T */</span><span class="w"></span>

<span class="w">    </span><span class="k">fn</span> <span class="nf">foo</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="cm">/* Here we only have that `Self : Trait_&lt;'thing&gt;`, not that `Self : Trait`. */</span><span class="w"></span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">thing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">();</span><span class="w"> </span><span class="c1">// local</span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">Self</span>::<span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="cm">/* 'local */</span><span class="w"> </span><span class="n">thing</span><span class="p">);</span><span class="w"> </span><span class="c1">// Error, we don't have `'local : 'thing`</span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>And so the full workaround, at least while <code>partial impl</code>s (<code>default impl</code>s) are not around either, is to use a helper super trait:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">trait</span><span class="w"> </span><span class="n">Trait_</span><span class="o">&lt;'</span><span class="na">thing</span><span class="o">&gt;</span><span class="w"> </span>: <span class="nc">Foo</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">T</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">get</span><span class="w"> </span><span class="p">(</span><span class="n">_</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">thing</span> <span class="p">())</span><span class="w"> </span>-&gt; <span class="nc">Self</span>::<span class="n">T</span>:
<span class="p">}</span><span class="w"></span>

<span class="k">trait</span><span class="w"> </span><span class="n">Foo</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="k">fn</span> <span class="nf">foo</span><span class="p">();</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span><span class="w"> </span>: <span class="o">?</span><span class="nb">Sized</span><span class="o">&gt;</span><span class="w"> </span><span class="n">Foo</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">T</span><span class="w"> </span><span class="k">where</span><span class="w"> </span><span class="n">T</span><span class="w"> </span>: <span class="nc">Trait</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">foo</span><span class="w"> </span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">thing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">();</span><span class="w"> </span><span class="c1">// local</span>
<span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">_</span>: <span class="o">&lt;</span><span class="bp">Self</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">Trait_</span><span class="o">&lt;'</span><span class="nb">_</span><span class="o">&gt;&gt;</span>::<span class="n">T</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">Self</span>::<span class="n">get</span><span class="p">(</span><span class="o">&amp;</span><span class="cm">/* 'local */</span><span class="w"> </span><span class="n">thing</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="229212348"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/229212348" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Philipp Korber <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#229212348">(Mar 07 2021 at 19:39)</a>:</h4>
<p>A afmhmhnhnmhnhnnnhnhhhhhnnggh</p>



<a name="231210926"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231210926" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Philipp Korber <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231210926">(Mar 21 2021 at 11:36)</a>:</h4>
<p>Um, sorry. I have no idea what happened <span aria-label="joy" class="emoji emoji-1f602" role="img" title="joy">:joy:</span></p>
<p>Especially given that it was sent at a time I was still asleep as far as I know... This is really strange.</p>



<a name="231211368"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231211368" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Laurențiu <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231211368">(Mar 21 2021 at 11:46)</a>:</h4>
<p>Got a cat or chicken?</p>



<a name="231211474"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231211474" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Philipp Korber <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231211474">(Mar 21 2021 at 11:48)</a>:</h4>
<p>No, it also happened on my phone app in one of ~50 unread topics which happened to be one of the ~3 topics I actually did read roughly 3 hours later. It's a total mystery for me.</p>



<a name="231461549"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231461549" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> john xu <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231461549">(Mar 23 2021 at 12:32)</a>:</h4>
<p>(deleted)</p>



<a name="231462098"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231462098" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> john xu <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231462098">(Mar 23 2021 at 12:36)</a>:</h4>
<p><span class="user-mention silent" data-user-id="243558">Steven Fackler</span> <a href="#narrow/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F/near/227610360">said</a>:</p>
<blockquote>
<p>Oh yeah, one of the main problems is that if you want your iterator to return a value borrowed from itself, that just doesn't really work with respect to naming the trait it implements.</p>
</blockquote>
<p>This also block my work. When I use associated type as struct member.</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">MyStruct</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">SomeTrait</span><span class="o">&gt;</span><span class="w">  </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">member</span>: <span class="o">&lt;</span><span class="n">T</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">SomeTrait</span><span class="o">&gt;</span>::<span class="n">AssociatedType</span><span class="o">&lt;'???&gt;</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="231518432"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231518432" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231518432">(Mar 23 2021 at 18:20)</a>:</h4>
<p>That looks to me like an issue with any self-referential borrow more than anything else; could you provide more context?</p>



<a name="231620112"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231620112" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> john xu <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231620112">(Mar 24 2021 at 11:45)</a>:</h4>
<p><span class="user-mention silent" data-user-id="232018">Daniel Henry-Mantilla</span> <a href="#narrow/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F/near/231518432">said</a>:</p>
<blockquote>
<p>That looks to me like an issue with any self-referential borrow more than anything else; could you provide more context?</p>
</blockquote>
<p>Yeah, Forexample MyStruct want to hold value generated by another member who's type is bound to a GAT trait.<br>
my code and question:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">trait</span><span class="w"> </span><span class="n">MyTrait</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">Item</span><span class="o">&lt;'</span><span class="na">a</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">foo</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">Self</span>::<span class="n">Item</span><span class="o">&lt;'</span><span class="nb">_</span><span class="o">&gt;</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">struct</span> <span class="nc">MyStruct</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">MyTrait</span><span class="o">&gt;</span><span class="w">  </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">t</span>: <span class="nc">T</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">t_item</span>: <span class="nc">T</span>::<span class="n">Item</span><span class="o">&lt;'???&gt;</span><span class="p">,</span><span class="w"> </span><span class="c1">// what about here's lifetime</span>
<span class="p">}</span><span class="w"></span>

<span class="k">impl</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">MyTrait</span><span class="o">&gt;</span><span class="w"> </span><span class="n">MyStruct</span><span class="o">&lt;</span><span class="n">T</span>: <span class="nc">MyTrait</span><span class="o">&gt;</span><span class="w">  </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">hold_item</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">         </span><span class="c1">// MyStruct want to hold item form T</span>
<span class="w">         </span><span class="bp">self</span><span class="p">.</span><span class="n">t_item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">t</span><span class="p">.</span><span class="n">foo</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<a name="231736566"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/What%20will%20GATs%20allow%20streaming%20iterators%20to%20do%20differently%3F/near/231736566" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/What.20will.20GATs.20allow.20streaming.20iterators.20to.20do.20differently.3F.html#231736566">(Mar 25 2021 at 01:49)</a>:</h4>
<p>I don't find this to be an issue with GATs, but with to-become-self-referential structs. That is, let's stop being generic over <code>T</code>, and choose a specific type that implements <code>MyTrait</code>. For the sake of the example, say it's:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">impl</span><span class="w"> </span><span class="n">MyTrait</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Foo</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">type</span> <span class="nc">Item</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;'</span><span class="na">foo</span><span class="w"> </span><span class="n">Foo</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">foo</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="w"> </span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">foo</span> <span class="nc">Foo</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kp">&amp;</span><span class="o">'</span><span class="na">foo</span> <span class="nc">Foo</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="bp">self</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>What would the definition of <code>MyStruct::&lt;Foo&gt;</code> be? It wouldn't need GATs, since it could be written as</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">MyStructFoo</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">t</span>: <span class="nc">Foo</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">t_item</span>: <span class="kp">&amp;</span><span class="o">'???</span><span class="w"> </span><span class="n">Foo</span><span class="p">,</span><span class="w"> </span><span class="c1">// No GATs</span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Granted, for concrete types such as references we have a way to express an <code>'unsafe</code> / <code>'erased</code> lifetime thanks to raw pointers:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">MyStructFoo</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">t</span>: <span class="nc">Foo</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">t_item</span>: <span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="n">Foo</span><span class="p">,</span><span class="w"> </span><span class="cm">/* we mean `&amp;'unsafe Foo` */</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>The other option, and usually more correct option, is to make the whole struct generic over the lifetime of its own self-borrow:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">MyStructFoo</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">t</span>: <span class="nc">Foo</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">t_item</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">foo</span> <span class="nc">Foo</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">impl</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="w"> </span><span class="n">MyStructFoo</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">hold_item</span><span class="w"> </span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">foo</span> <span class="nc">mut</span><span class="w"> </span><span class="n">MyStructFoo</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">         </span><span class="bp">self</span><span class="p">.</span><span class="n">t_item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">t</span><span class="p">.</span><span class="n">foo</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>where you can notice that, for given choice of type <code>MyStructFoo</code> and its lifetime parameter <code>&lt;'foo&gt;</code>, the borrow of <code>self</code> in <code>hold_item</code> is not generic, but fixed to <code>'foo</code>: that's the only way to feature a fully non-<code>unsafe</code> API.</p>
<hr>
<p>So, back to GATs, we'd end up with:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">struct</span> <span class="nc">MyStruct</span><span class="o">&lt;'</span><span class="na">foo</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="w"> </span>: <span class="nc">MyTrait</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">t</span>: <span class="nc">Foo</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="n">t_item</span>: <span class="o">&lt;</span><span class="n">T</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="n">MyTrait</span><span class="o">&gt;</span>::<span class="n">T</span><span class="o">&lt;'</span><span class="na">foo</span><span class="o">&gt;</span><span class="p">,</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">impl</span><span class="o">&lt;'</span><span class="na">foo</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="w"> </span>: <span class="nc">MyTrait</span><span class="o">&gt;</span><span class="w"> </span><span class="n">MyStructFoo</span><span class="o">&lt;'</span><span class="na">foo</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">hold_item</span><span class="w"> </span><span class="p">(</span><span class="bp">self</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">foo</span> <span class="nc">mut</span><span class="w"> </span><span class="n">MyStructFoo</span><span class="o">&lt;'</span><span class="na">foo</span><span class="p">,</span><span class="w"> </span><span class="n">T</span><span class="o">&gt;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">         </span><span class="bp">self</span><span class="p">.</span><span class="n">t_item</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">t</span><span class="p">.</span><span class="n">foo</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>